/*
 * Copyright (c) 2014 Luca Agostini, Alessandro Cantini, Alessandro Dignani
 *
 * This file is part of MeteoCal.
 *
 * MeteoCal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package it.polimi.se2.agostini_cantini_dignani.meteocal.entity;

import javax.persistence.*;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * @author Alessandro Cantini
 */
@Entity
@XmlAccessorType(XmlAccessType.NONE)
@NamedQueries({
		@NamedQuery(name = Event.findAll, query = "SELECT e FROM Event e")
})
public class Event implements Serializable {

	public static final String findAll = "Event.findAll";
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer eventId;

	@XmlAttribute
	@NotNull(message = "You must enter a title")
	@Size(min = 1, max = 45)
	private String title;

	@XmlElement
	@Size(max = 1023)
	private String description;

	@XmlElement
	@Size(max = 255)
	private String place;

	@XmlElement(defaultValue = "false")
	@NotNull
	private boolean outdoor;

	@XmlElement(name = "public", defaultValue = "false")
	@NotNull
	private boolean isPublic;

	@XmlElement
	@NotNull
	@Temporal(TemporalType.TIMESTAMP)
	private Date startTime;

	@XmlElement
	@NotNull
	@Temporal(TemporalType.TIMESTAMP)
	private Date endTime;

	@ManyToMany
	@JoinTable(name = "INVITATION")
	private List<User> invitedUsers;

	@ManyToMany
	@JoinTable(name = "DECLINATION")
	private List<User> usersWhoHaveDeclined;

	@ManyToMany(mappedBy = "events")
	private List<Calendar> participantCalendars;

	@XmlElement
	@NotNull
	@ManyToOne
	private User owner;

	@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
	private WeatherForecast weatherForecast;

	public Event() {
	}

	@AssertTrue
	public boolean isValid() {
		if (place == null && weatherForecast != null) {
			return false;
		}

		return startTime.before(endTime) &&
				(invitedUsers == null || !invitedUsers.contains(owner)) &&
				(usersWhoHaveDeclined == null || !usersWhoHaveDeclined.contains(owner));
	}

	public Integer getEventId() {
		return eventId;
	}

	public void setEventId(Integer eventId) {
		this.eventId = eventId;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getPlace() {
		return place;
	}

	public void setPlace(String place) {
		this.place = place;
	}

	public boolean isOutdoor() {
		return outdoor;
	}

	public void setOutdoor(boolean outdoor) {
		this.outdoor = outdoor;
	}

	public boolean isPublic() {
		return isPublic;
	}

	public void setPublic(boolean isPublic) {
		this.isPublic = isPublic;
	}

	public Date getStartTime() {
		return startTime;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public Date getEndTime() {
		return endTime;
	}

	public void setEndTime(Date endTime) {
		this.endTime = endTime;
	}

	public List<User> getInvitedUsers() {
		return invitedUsers;
	}

	public void setInvitedUsers(List<User> invitedUsers) {
		this.invitedUsers = invitedUsers;
	}

	public List<User> getUsersWhoHaveDeclined() {
		return usersWhoHaveDeclined;
	}

	public void setUsersWhoHaveDeclined(List<User> usersWhoHaveDeclined) {
		this.usersWhoHaveDeclined = usersWhoHaveDeclined;
	}

	public List<Calendar> getParticipantCalendars() {
		return participantCalendars;
	}

	public void setParticipantCalendars(List<Calendar> participantCalendars) {
		this.participantCalendars = participantCalendars;
	}

	public User getOwner() {
		return owner;
	}

	public void setOwner(User owner) {
		this.owner = owner;
	}

	public WeatherForecast getWeatherForecast() {
		return weatherForecast;
	}

	public void setWeatherForecast(WeatherForecast weatherForecast) {
		this.weatherForecast = weatherForecast;
	}

	public Long duration() {
		return endTime.getTime() - startTime.getTime();
	}

	@Override
	public int hashCode() {
		int hash = 0;
		hash += (eventId != null ? eventId.hashCode() : 0);
		return hash;
	}

	@Override
	public boolean equals(Object object) {
		if (!(object instanceof Event)) {
			return false;
		}
		Event other = (Event) object;
		if ((this.eventId == null && other.eventId != null) || (this.eventId != null && !this.eventId.equals(other.eventId))) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		return "[Event: " + title + ", id: " + eventId + " ]";
	}
}
